/*
 * Simulation.h
 *
 *  Created on: Feb 2, 2012
 *      Author: falko
 */

#ifndef SIMULATION_H_
#define SIMULATION_H_

#include "CurrentPath.h"
#include <string>
#include <iostream>
#include <sstream>
#include <map>
#include <utility>
#include <iterator>

namespace falko
{

struct particle;
enum particle_type
{
	DEFAULT = -1,
	ELECTRON,
	PROTON,
	H_PLUS,
};

class ParticleFactory
{
public:
	static void Generate(particle * p, particle_type type);

private:

	static void clear(particle * p);

	static void electron(particle * p);

	static void proton(particle * p);

	static void h_plus(particle * p);

	static int nextID()
	{
		static uint i = 0;
		return ++i;
	}
};

struct particle
{
public:
	particle(particle_type type) : mass_(), abs_charge_(), position_(), velocity_(), acceleration_()
	{
		ParticleFactory::Generate(this, type);
	}
	~particle(){}

	particle_type type_;
	uint    id_;
	hpf_t   mass_;
	hpf_t   abs_charge_;  //amount of charge
	int     charge_;      //postive = 1 nagitave = -1
	hpv3d_t position_;
	hpv3d_t velocity_;
	hpv3d_t acceleration_;
};


class SimulationFileWriter
{
public:
	SimulationFileWriter()
	{	}
	~SimulationFileWriter();

	void write (particle * p, hpf_t const &time);

	void setName(std::string s) { simulation_name_ = s; }

private:
	struct particle_writers
	{
		particle_writers() {}
		particle_writers (const char * pos, const char * vel)
			: pos_file_(pos), vel_file_(vel)
		{}
		HpFileWriter pos_file_;
		HpFileWriter vel_file_;
	};

	typedef std::map<particle*, particle_writers*> WriterMap;
	WriterMap writers_map_;
	std::string simulation_name_;

	void writeNewParticle(particle * p);

	void writeParticleData(particle * p, HpFileWriter &w);
};



class ParticleSource
{
public:
	ParticleSource(particle_type t, hpf_t v, uint max, hpv3d_t c, hpv3d_t dir);
	~ParticleSource();
	particle * getParticle();
	operator bool() const
	{
		return max_emissions_ > 0;
	}

private:
	particle_type type_;
	std::vector<particle*> particles_;
	hpf_t voltage_;
	uint max_emissions_;
	hpv3d_t center_;
	hpv3d_t emision_dir_;
};


class Simulation
{
public:
	enum simulation_type_
	{
		GENERATE_VECTOR_FIELD,
		PARTICLE_TRACE,
	};

	Simulation() : iterations_(0), time_(0.0), ion_source_(NULL) {}

	~Simulation();

	void run(const char * file);

private:
	simulation_type_ type_;
	uint iterations_;
	SimulationFileWriter file_writter_;
	std::vector<particle*> particles_;
	hpf_t time_;
	hpf_t delta_time_;
	MagneticField mag_field_;
	ParticleSource *ion_source_;
	std::string simulation_name_;

	void parseFile(const char * file);

	void initSimulation(std::vector<std::string> &init_data);

	void addCoil(std::vector<std::string> &init_data);

	void initIonSource(std::vector<std::string> &init_data);

	void particleTrace();

	void generateVectorField();

	void step();

	void calculateAcceleration(particle const * pa,
							   hpv3d_t const &b_field,
							   hpv3d_t &acceleration);
};


void plotVectorField(char const * file_name);










}
#endif /* SIMULATION_H_ */
